import os
import time
import requests
import sys
import importlib.util
import sys
import importlib.util
import binascii
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
from typing import Optional
from bs4 import BeautifulSoup


# 配置文件路径建议通过环境变量或外部配置传入，避免硬编码敏感路径

# 复用 config_api.py 的 save_config
CONFIG_API_PATH = os.path.join(os.path.dirname(__file__), "config_api.py")
spec = importlib.util.spec_from_file_location("config_api", CONFIG_API_PATH)
config_api = importlib.util.module_from_spec(spec)
sys.modules["config_api"] = config_api
spec.loader.exec_module(config_api)

# 公钥从配置文件读取，避免代码中出现明文
def get_pubkey():
    config = get_config()
    return config.get('bilibili', {}).get('pubkey', '')

# 公钥从配置文件读取，避免代码中出现明文
def get_pubkey():
    config = get_config()
    return config.get('bilibili', {}).get('pubkey', '')

def get_config():
    return config_api.get_config()

def save_config(config):
    # 直接复用 config_api.py 的 save_config
    config_api.save_config(config)

def get_cookie_and_refresh_token():
    config = get_config()
    bili = config.get('bilibili', {})
    cookie = bili.get('cookie', {})
    refresh_token = bili.get('refresh_token', None)
    return cookie, refresh_token

def save_cookie_and_refresh_token(cookie: dict, refresh_token: Optional[str]):
    config = get_config()
    if 'bilibili' not in config:
        config['bilibili'] = {}
    config['bilibili']['cookie'] = cookie
    if refresh_token:
        config['bilibili']['refresh_token'] = refresh_token
    save_config(config)

def check_cookie_need_refresh(cookie: dict) -> tuple[bool, int]:
    url = 'https://passport.bilibili.com/x/passport-login/web/cookie/info'
    cookies = {
        'SESSDATA': cookie.get('SESSDATA', ''),
        'DedeUserID': cookie.get('DedeUserID', ''),
        'bili_jct': cookie.get('bili_jct', '')
    }
    params = {'csrf': cookie.get('bili_jct', '')}
    resp = requests.get(url, cookies=cookies, params=params, timeout=10)
    data = resp.json()
    if data.get('code') == 0:
        return data['data']['refresh'], data['data']['timestamp']
    return False, int(time.time() * 1000)

def get_correspond_path(ts: int) -> str:
    pubkey = (
        "-----BEGIN PUBLIC KEY-----\n"
        "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLgd2OAkcGVtoE3ThUREbio0Eg\n"
        "Uc/prcajMKXvkCKFCWhJYJcLkcM2DKKcSeFpD/j6Boy538YXnR6VhcuUJOhH2x71\n"
        "nzPjfdTcqMz7djHum0qSZA0AyCBDABUqCrfNgCiJ00Ra7GmRj+YCK1NJEuewlb40\n"
        "JNrRuoEUXpabUzGB8QIDAQAB\n"
        "-----END PUBLIC KEY-----"
    )
    key = RSA.importKey(pubkey)
    cipher = PKCS1_OAEP.new(key, SHA256)
    encrypted = cipher.encrypt(f'refresh_{ts}'.encode())
    return binascii.b2a_hex(encrypted).decode()

def get_refresh_csrf(correspond_path: str, cookie: dict) -> str:
    url = f'https://www.bilibili.com/correspond/1/{correspond_path}'
    cookies = {
        'SESSDATA': cookie.get('SESSDATA', ''),
        'DedeUserID': cookie.get('DedeUserID', ''),
        'bili_jct': cookie.get('bili_jct', '')
    }
    resp = requests.get(url, cookies=cookies, timeout=10)
    soup = BeautifulSoup(resp.text, 'html.parser')
    div = soup.find('div', id='1-name')
    if div:
        return div.text.strip()
    raise Exception('refresh_csrf not found')

def refresh_cookie(cookie: dict, refresh_token: str, refresh_csrf: str) -> tuple[dict, str]:
    url = 'https://passport.bilibili.com/x/passport-login/web/cookie/refresh'
    cookies = {
        'SESSDATA': cookie.get('SESSDATA', ''),
        'DedeUserID': cookie.get('DedeUserID', ''),
        'bili_jct': cookie.get('bili_jct', '')
    }
    data = {
        'csrf': cookie.get('bili_jct', ''),
        'refresh_csrf': refresh_csrf,
        'source': 'main_web',
        'refresh_token': refresh_token
    }
    resp = requests.post(url, cookies=cookies, data=data, timeout=10)
    res = resp.json()
    if res.get('code') == 0:
        # 新cookie在Set-Cookie头部，refresh_token在data里
        new_refresh_token = res['data'].get('refresh_token', refresh_token)
        # 自动提取Set-Cookie中的新cookie
        new_cookie = cookie.copy()
        set_cookie_headers = resp.headers.get('Set-Cookie')
        if set_cookie_headers:
            # 兼容多头部合并的情况
            if isinstance(set_cookie_headers, str):
                cookies_list = set_cookie_headers.split(',')
            else:
                cookies_list = set_cookie_headers
            for c in cookies_list:
                for k in ['SESSDATA', 'DedeUserID', 'bili_jct']:
                    if k in c:
                        val = c.split(f'{k}=')[-1].split(';')[0]
                        new_cookie[k] = val
        return new_cookie, new_refresh_token
    raise Exception(f"cookie刷新失败: {res}")

def confirm_refresh(cookie: dict, old_refresh_token: str):
    url = 'https://passport.bilibili.com/x/passport-login/web/confirm/refresh'
    cookies = {
        'SESSDATA': cookie.get('SESSDATA', ''),
        'DedeUserID': cookie.get('DedeUserID', ''),
        'bili_jct': cookie.get('bili_jct', '')
    }
    data = {
        'csrf': cookie.get('bili_jct', ''),
        'refresh_token': old_refresh_token
    }
    resp = requests.post(url, cookies=cookies, data=data, timeout=10)
    res = resp.json()
    if res.get('code') == 0:
        return True
    return False

def auto_refresh_cookie():
    cookie, refresh_token = get_cookie_and_refresh_token()
    if not cookie or not refresh_token:
        print('[auto_refresh_cookie] 缺少cookie或refresh_token，无法自动续期')
        return
    need_refresh, ts = check_cookie_need_refresh(cookie)
    print(f'[auto_refresh_cookie] need_refresh={need_refresh}, ts={ts}')
    if not need_refresh:
        print('[auto_refresh_cookie] 当前cookie无需续期')
        return
    correspond_path = get_correspond_path(ts)
    print(f'[auto_refresh_cookie] correspond_path={correspond_path}')
    refresh_csrf = get_refresh_csrf(correspond_path, cookie)
    print(f'[auto_refresh_cookie] refresh_csrf={refresh_csrf}')
    old_refresh_token = refresh_token
    new_cookie, new_refresh_token = refresh_cookie(cookie, refresh_token, refresh_csrf)
    print(f'[auto_refresh_cookie] 刷新后refresh_token={new_refresh_token}')
    save_cookie_and_refresh_token(new_cookie, new_refresh_token)
    confirm_refresh(new_cookie, old_refresh_token)
    print('[auto_refresh_cookie] cookie自动续期完成')

if __name__ == '__main__':
    auto_refresh_cookie()
